/*********************************************************
 *
 *  Ports all the way down - patwd
 *  ------------------------------
 *
 *  pcap_foo.c
 *
 *  Copyright (C) 2012 by Sebastian Roschke (bykhee@gmail.com)
 *
 *  Pcap related functionality, i.e. functions and structures for capturing
 *  network packets. Current filtering based on SYN and ACK flags.
 *
 *  Distributed under the terms and conditions of GNU LGPL.
 *
 */

#include "pcap_foo.h"
#include "debug.h"
#include "alloc-inl.h"

#define LBUFSIZE 256
#define PCAP_NET_UNKNOWN 0xffffffff

void syn_mode_cfg() {
  // Open pcap session to sniff traffic
  struct bpf_program fp; /* The compiled filter */

  // The filter needs to look for syn packets in this case and to filter for specific source IPs
  char filter_exp[] = "tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) == 0"; /* The filter expression */

  bpf_u_int32 net = PCAP_NET_UNKNOWN;

  handle = pcap_open_live((char*)dev, BUFSIZ, 1, 1000, errbuf);

  u8* lstr = NULL;
  if (!handle) {
    lstr = alloc_printf("Couldn't open device %s: %s\n", dev, errbuf);
    log_error(lstr);
    ck_free(lstr);
    exit(2);
  }

  linkl = pcap_datalink(handle);
  if (linkl != DLT_EN10MB && linkl != DLT_LINUX_SLL) {
    lstr = alloc_printf("Link layer type not supported! Link layer is %s\n", pcap_datalink_val_to_name((int)linkl));
    log_error(lstr);
    ck_free(lstr);
    exit(2);
  } else {
    lstr = alloc_printf("Link layer is %s\n", pcap_datalink_val_to_name((int)linkl));
    logg(lstr);
    ck_free(lstr);

    if (linkl == DLT_EN10MB) {

    }
  }

  /* Compile and apply the filter */
  if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
    lstr = alloc_printf("Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
    log_error(lstr);
    ck_free(lstr);
    exit(2);
  }
  if (pcap_setfilter(handle, &fp) == -1) {
    lstr = alloc_printf("Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
    log_error(lstr);
    ck_free(lstr);
    exit(2);
  }
}

void syn_mode_sniffing() {
  pcap_loop(handle, -1, handle_packet, NULL);
}

int get_ethh_size(void* pkt, const struct pcap_pkthdr *hdr) {
  return ETHERNET_HEADER;
}

int get_sllh_size(void* pkt, const struct pcap_pkthdr *hdr) {
  return SLL_HEADER;
}
